﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once
#include "GcmpMathInterface.h"

#include "GbmpConstants.h"
#include "MathUtils.h"
#include "DebugMessage.h"
#include "GbmpTypeDefs.h"
#include <sstream>
#include <iomanip>

namespace gcmp
{
    /// \brief  四维向量的定义
    ///
    /// 
    class GCMP_MATH_INTERFACE_EXPORT Vector4d
    {
    public:
        DEFINE_VISUAL_TYPE_DOUBLE()

    public:

        /// \brief   创建四维向量
        ///
        /// \param x X分量
        /// \param y Y分量
        /// \param z Z分量
        /// \param w W分量
        /// \return  四维向量
        static  Vector4d Create(double x, double y, double z, double w);

        /// \brief  创建四维零向量
        ///
        /// \return  四维零向量
        static Vector4d CreateZeroVector4d();

        /// \brief 获取X分量
        ///
        /// \return  X分量
        double GetX() const;

        /// \brief 获取Y分量
        ///
        /// \return  Y分量
        double GetY() const;

        /// \brief 获取Z分量
        ///
        /// \return  Z分量
        double GetZ() const;
        
        /// \brief 获取W分量
        ///
        /// \return  W分量
        double GetW() const;

        /// \brief    设置该向量的X和Y分量
        ///
        /// \param x  X分量
        /// \param y  Y分量
        /// \param z  Z分量
        /// \param w  W分量
        /// \return  true:成功， false：失败
        bool Set(double x, double y, double z, double w);

        /// \brief   设置该向量的X分量
        ///
        /// \param x X分量
        /// \return  true:成功， false：失败
        bool SetX(double x);

        /// \brief   设置该向量的Y分量
        ///
        /// \param y Y分量
        /// \return  true:成功， false：失败
        bool SetY(double y);

        /// \brief   设置该向量的Z分量
        ///
        /// \param z Z分量
        /// \return  true:成功， false：失败
        bool SetZ(double z);

        /// \brief   设置该向量的W分量
        ///
        /// \param w W分量
        /// \return  true:成功， false：失败
        bool SetW(double w);

        /// \brief    判断向量在给定误差下是否零向量
        ///
        /// \param typeTol  误差
        /// \return  true:是， false：否
        bool IsZero(double typeTol = gcmp::Constants::DOUBLE_EPS) const;

        /// \brief   判断向量在给定误差下是否单位向量
        ///
        /// \param typeTol  误差
        /// \return true:是， false：否
        bool IsUnit(double typeTol = gcmp::Constants::DOUBLE_EPS) const;

        /// \brief   计算向量的长度
        ///
        /// \return  向量的长度
        double Length() const;

        /// \brief   计算向量长度的平方
        ///
        /// \return  向量长度的平方
        double SqrLength() const;

        /// \brief     向量的单位化
        ///
        /// \param eps 容差
        /// \return   单位化前向量的长度
        double Normalize(double eps = gcmp::Constants::DOUBLE_EPS);

        /// \brief   计算向量与给定向量的点积
        ///
        /// \param vecSrc  给定向量
        /// \return   点积
        double Dot(const Vector4d & vecSrc) const;

    public:

        /// \brief   默认构造函数
        /// 
        Vector4d();

        /// \brief    通过长度为4的数组构造四维向量
        ///
        /// \param vec  长度为4的数组
        /// 
        explicit Vector4d(double vec[4]);

        /// \brief    通过向量的X，Y，Z, W分量构造四维向量
        ///
        /// \param x  X分量
        /// \param y  Y分量
        /// \param z  Z分量
        /// \param w  W分量
        /// 
        Vector4d(double x, double y, double z, double w);

        /// \brief   拷贝构造函数
        ///
        /// \param src  另一个Vector2
        ///
        Vector4d(const Vector4d& src);

        /// \brief  获取X分量
        ///
        /// \return  X分量
        double X() const;

        /// \brief  获取Y分量
        ///
        /// \return  Y分量
        double Y() const;

        /// \brief  获取Z分量
        ///
        /// \return  Z分量
        double Z() const;

        /// \brief  获取W分量
        ///
        /// \return  W分量
        double W() const;

        /// \brief  获取X分量的引用
        ///
        /// \return  X分量的引用
        double& X();

        /// \brief  获取Y分量的引用
        ///
        /// \return  Y分量的引用
        double& Y();

        /// \brief  获取Z分量的引用
        /// \return  Z分量的引用
        double& Z();

        /// \brief  获取W分量的引用
        ///
        /// \return  W分量的引用
        double& W();

        /// \brief    按照索引获取向量的分量
        ///
        /// \param nIndex 索引，由调用者确保分量索引的有效性
        /// \return  向量分量值的引用
        double& operator[](int nIndex);

        /// \brief    按照索引获取向量的分量
        ///
        /// \param nIndex 索引，由调用者确保分量索引的有效性
        /// \return  向量分量值
        double operator[](int nIndex) const;

        /// \brief    该向量乘给定数值
        ///
        /// \param d 乘数
        /// \return 结果向量
        Vector4d & operator *=(const double d);

        /// \brief    该向量除给定数值
        ///
        /// \param d 除数，调用者确保输入参数的有效性，不能为0
        /// \return 结果向量
        Vector4d & operator /=(const double d);

        /// \brief    向量与给定向量求和
        ///
        /// \param vecSrc 给定向量
        /// \return 和向量的引用
        Vector4d & operator +=(const Vector4d & vecSrc);

        /// \brief    向量与给定向量求差
        ///
        /// \param vecSrc 给定向量
        /// \return 差向量引用
        Vector4d & operator -=(const Vector4d & vecSrc);

        /// \brief    向量反向
        ///
        /// \return 反向量
        Vector4d operator-() const;

        /// \brief   包围盒对象按照规定格式字符串输出
        ///
        /// \return  字符串
        std::wstring GetStringForDebug() const;

    private:
        double m_xyzw[4];
    public:
        static const Vector4d UnitX;
        static const Vector4d UnitY;
        static const Vector4d UnitZ;
        static const Vector4d UnitW;
        static const Vector4d Zero;
    };

    /// \brief    向量乘给定数值
    ///
    /// \param vecSrc 给定向量
    /// \param d 乘数
    /// \return 结果向量
    GCMP_MATH_INTERFACE_EXPORT Vector4d operator *(const Vector4d & vecSrc, const double d);

    /// \brief    数值乘给定向量
    ///
    /// \param d 乘数
    /// \param vecSrc 给定向量
    /// \return 结果向量
    GCMP_MATH_INTERFACE_EXPORT Vector4d operator *(const double d, const Vector4d & vecSrc);

    /// \brief    两个向量的点乘
    ///
    /// \param v1   向量1
    /// \param v2   向量2
    /// \return 点乘结果
    GCMP_MATH_INTERFACE_EXPORT double operator *(const Vector4d & v1, const Vector4d & v2);

    /// \brief    向量除以一个数
    ///
    /// \param vecSrc  被除向量
    /// \param d       除数
    /// \return 结果向量
    GCMP_MATH_INTERFACE_EXPORT Vector4d operator /(const Vector4d& vecSrc, const double d);

    /// \brief    两个向量的加法，即向量的每个分量相加
    ///
    /// \param v1   向量1
    /// \param v2   向量2
    /// \return 向量的和
    GCMP_MATH_INTERFACE_EXPORT Vector4d operator +(const Vector4d& v1, const Vector4d& v2);

    /// \brief    两个向量的减法，即向量1的每个分量减去向量2的每个分量
    ///
    /// \param v1   向量1
    /// \param v2   向量2
    /// \return 向量的差
    GCMP_MATH_INTERFACE_EXPORT Vector4d operator -(const Vector4d& v1, const Vector4d& v2);

    /// \brief    判断向量是否相同
    ///
    /// \param v1   向量1
    /// \param v2   向量2
    /// \return true: 相同   false: 不同
    GCMP_MATH_INTERFACE_EXPORT bool operator ==(const Vector4d& v1, const Vector4d& v2);

    /// \brief    判断向量是否不同
    ///
    /// \param v1   向量1
    /// \param v2   向量2
    /// \return true: 不同   false: 相同
    GCMP_MATH_INTERFACE_EXPORT bool operator !=(const Vector4d& v1, const Vector4d& v2);

} // namespace





